﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using 文件管理;

namespace util
{
    internal static class Util
    {

        public static string ByteArrayToHexString(byte[] ba)
        {
            StringBuilder hex = new StringBuilder(ba.Length * 2);
            foreach (byte b in ba)
            {
                hex.AppendFormat("{0:x2}", b);
            }
            return hex.ToString();
        }

    

        public static  byte[] ReceiveExact(Socket socket, int totalBytesToRead)
        {
            byte[] buffer = new byte[totalBytesToRead];
            int totalBytesReceived = 0;
            int bytesRead;

            while (totalBytesReceived < totalBytesToRead)
            {
                // 确保套接字是阻塞的，或者处理非阻塞模式下的逻辑（比如使用Socket.Poll）
                // 在这个例子中，我们假设套接字是阻塞的
                bytesRead = socket.Receive(buffer, totalBytesReceived, totalBytesToRead - totalBytesReceived, SocketFlags.None);
                if (bytesRead == 0)
                {
                    // 对于阻塞套接字，这通常意味着连接已经关闭
                    return null;
                }

                totalBytesReceived += bytesRead;
            }

            // 如果只需要部分缓冲区的数据，可以返回一个新的字节数组
            // 但在这个例子中，我们直接返回了整个缓冲区，因为它已经填充了所需的数据
            return buffer;
        }

        public static long getLong(byte[] buffer)
        {
            return buffer[0] << 56 | buffer[1] << 48 | buffer[2] << 40 | buffer[3] <<32| buffer[4] <<24| buffer[5] <<16| buffer[6] <<8| buffer[7];
        }

        public static byte[] Int32ToBigEndianBytes(int value)
        {
            // 使用 BitConverter 获取字节数组
            byte[] bytes = BitConverter.GetBytes(value);

            // 检查系统字节序，如果是小端模式则反转字节顺序
            if (!BitConverter.IsLittleEndian)
            {
                // 如果系统已经是大端模式，则不需要转换
                return bytes;
            }
            else
            {
                // 创建一个新的字节数组并反转字节顺序
                byte[] bigEndianBytes = new byte[4];
                bigEndianBytes[0] = bytes[3];
                bigEndianBytes[1] = bytes[2];
                bigEndianBytes[2] = bytes[1];
                bigEndianBytes[3] = bytes[0];
                return bigEndianBytes;
            }
        }

        public static byte[] Int64ToBigEndianBytes(long value)
        {
            // 使用 BitConverter 获取字节数组
            byte[] bytes = BitConverter.GetBytes(value);

            // 检查系统字节序，如果是小端模式则反转字节顺序
            if (BitConverter.IsLittleEndian)
            {
                // 创建一个新的字节数组并反转字节顺序
                Array.Reverse(bytes);
            }
            // 如果系统已经是大端模式，则不需要转换，直接返回bytes

            return bytes;
        }

        public static bool ReceiveAndSaveData(Socket socket, long bytesToRead, string filePath, Action<int> callBack)
        {
            try
            {
                Console.WriteLine(filePath);
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                {
                    byte[] buffer = new byte[4096]; // 缓冲区大小，可以根据需要调整
                    long totalBytesReceived = 0;

                    while (totalBytesReceived < bytesToRead)
                    {
                        int bytesRead = socket.Receive(buffer);

                        if (bytesRead == 0)
                        {
                            // 如果读取到0字节，通常意味着连接已经关闭（TCP连接中）
                            throw new IOException("连接意外关闭，未能读取到足够的数据。");
                        }

                        // 写入实际读取到的字节数，而不是缓冲区的全部大小
                        fs.Write(buffer, 0, bytesRead);
                        totalBytesReceived += bytesRead;

                        // 可选：打印接收进度
                        Console.WriteLine($"已接收 {totalBytesReceived}/{bytesToRead} 字节");
                        int r = (int)(totalBytesReceived * 100 / bytesToRead);
                        callBack(r);
                    }

                    Console.WriteLine($"已成功接收 {totalBytesReceived} 字节并保存到 {filePath}");
                    return true;
                }
            }
            catch (SocketException ex)
            {
                Console.WriteLine($"Socket异常: {ex.Message}");
                FileLogger.Debug($"Socket异常: {ex.Message}");
            }
            catch (IOException ex)
            {
                Console.WriteLine($"IO异常: {ex.Message}");
                FileLogger.Debug($"IO异常: {ex.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生错误: {ex.Message}");
                FileLogger.Debug($"发生错误: {ex.Message}");
            }
            finally
            {
                
            }
            return false;
        }

        public static bool SendFile(Socket socket, string filePath, Action<int> callBack)
        {
            try
            {
                // 读取文件路径的UTF-8字节
                string filePathUtf8 = filePath.Substring(filePath.IndexOf('\\') + 1).Replace("\\", "/");
                byte[] filePathBytes = Encoding.UTF8.GetBytes(filePathUtf8);

                // 准备要发送的元数据
                using (MemoryStream msMeta = new MemoryStream())
                {
                    // 写入开始标志（可以根据需要自定义）
                    msMeta.WriteByte(0x00);
                    msMeta.WriteByte(0xF6);

                    // 写入路径字符串的UTF-8字节长度（4个字节，大端模式）
                    msMeta.Write(Int32ToBigEndianBytes(filePathBytes.Length), 0, 4);

                    // 写入路径字符串的UTF-8字节
                    msMeta.Write(filePathBytes, 0, filePathBytes.Length);
                    long fileLength = 0;
                    // 写入文件长度的8个字节（大端模式）
                    using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                    {
                        fileLength = fs.Length;
                        msMeta.Write(Int64ToBigEndianBytes(fileLength), 0, 8);
                    }

                    // 获取完整的元数据数组
                    byte[] metaData = msMeta.ToArray();

                    // 发送元数据到Socket
                    socket.Send(metaData);

                    // 准备发送文件数据（分块）
                    const int bufferSize = 4096; // 缓冲区大小，可以根据需要调整
                    byte[] buffer = new byte[bufferSize];
                    using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                    {
                        int bytesRead;
                        long totalRead = 0;
                        while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            socket.Send(buffer, 0, bytesRead, SocketFlags.None);
                            totalRead += bytesRead;
                            int r = (int)(totalRead*100 / fileLength);
                            callBack(r);
                        }
                    }

                    Console.WriteLine($"文件 {filePath} 已成功发送到Socket。");
                    return true;
                }
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine($"文件未找到: {ex.Message}");
            }
            catch (SocketException ex)
            {
                Console.WriteLine($"Socket异常: {ex.Message}");
            }
            catch (IOException ex)
            {
                Console.WriteLine($"IO异常: {ex.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生错误: {ex.Message}");
            }
            return false;
        }


        public static bool SendFileToPath(Socket socket, string filePath, string rpath,Action<int> callBack)
        {
            try
            {
                byte[] filePathBytes = Encoding.UTF8.GetBytes(rpath);

                // 准备要发送的元数据
                using (MemoryStream msMeta = new MemoryStream())
                {
                    // 写入开始标志（可以根据需要自定义）
                    msMeta.WriteByte(0x0A);
                    msMeta.WriteByte(0xF4);

                    // 写入路径字符串的UTF-8字节长度（4个字节，大端模式）
                    msMeta.Write(Int32ToBigEndianBytes(filePathBytes.Length), 0, 4);

                    // 写入路径字符串的UTF-8字节
                    msMeta.Write(filePathBytes, 0, filePathBytes.Length);
                    long fileLength = 0;
                    // 写入文件长度的8个字节（大端模式）
                    using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                    {
                        fileLength = fs.Length;
                        msMeta.Write(Int64ToBigEndianBytes(fileLength), 0, 8);
                    }

                    // 获取完整的元数据数组
                    byte[] metaData = msMeta.ToArray();

                    // 发送元数据到Socket
                    socket.Send(metaData);

                    // 准备发送文件数据（分块）
                    const int bufferSize = 4096; // 缓冲区大小，可以根据需要调整
                    byte[] buffer = new byte[bufferSize];
                    using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                    {
                        int bytesRead;
                        long totalRead = 0;
                        while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            socket.Send(buffer, 0, bytesRead, SocketFlags.None);
                            totalRead += bytesRead;
                            int r = (int)(totalRead*100 / fileLength);
                            callBack(r);
                        }
                    }

                    Console.WriteLine($"文件 {filePath} 已成功发送到Socket。");
                    return true;
                }
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine($"文件未找到: {ex.Message}");
            }
            catch (SocketException ex)
            {
                Console.WriteLine($"Socket异常: {ex.Message}");
            }
            catch (IOException ex)
            {
                Console.WriteLine($"IO异常: {ex.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生错误: {ex.Message}");
            }
            return false;
        }

        // 遍历目录及其子目录，并发送文件
        public  static void TraverseAndSendFiles(string currentPath, string basePath, SocketClient socketClient)
        {
            // 检查目录是否存在
            if (!Directory.Exists(currentPath))
            {
                Console.WriteLine($"Directory {currentPath} does not exist.");
                return;
            }

            try
            {
                // 获取当前目录中的所有文件
                string[] files = Directory.GetFiles(currentPath);
                foreach (string file in files)
                {
                    // 计算文件的相对路径
                    string relativePath = GetRelativePath(basePath, file);
                    Console.WriteLine(relativePath);
                    // 发送文件
                    socketClient.doSendFile((file, true, relativePath));
                }

                // 获取当前目录中的所有子目录
                string[] directories = Directory.GetDirectories(currentPath);
                foreach (string directory in directories)
                {
                    // 递归调用以处理子目录
                    TraverseAndSendFiles(directory, basePath, socketClient);
                }
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine($"Access denied for {currentPath}: {ex.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred while processing {currentPath}: {ex.Message}");
            }
        }

        // 计算文件相对于给定基路径的相对路径
        private static string GetRelativePath(string basePath, string filePath)
        {
            // 确保 basePath 是以斜杠结尾的
            if (!basePath.EndsWith(Path.DirectorySeparatorChar.ToString()))
            {
                basePath += Path.DirectorySeparatorChar;
            }

            // 计算相对路径
            Uri basePathUri = new Uri(basePath);
            Uri filePathUri = new Uri(filePath);
            Uri relativeUri = basePathUri.MakeRelativeUri(filePathUri);

            return relativeUri.ToString();
        }


    }

}
